﻿using Common.Exceptions;
using System;
using System.Collections.Generic;
using System.Text;

namespace Common.Encrypt
{
    /// <summary>
    /// 敏感数据配置
    /// </summary>
    public class SensitiveDataConfig
    {
        /// <summary>
        /// 敏感数据配置
        /// </summary>
        public SensitiveDataConfig()
        {
            SetEnableFunc = () => { return true; };
        }
        /// <summary>
        /// 获取脱敏数据加密的Key，建议用Token
        /// </summary>
        public Func<string> SecretKeyFunc { get; set; }

        /// <summary>
        /// 获取忽略Key，建议从请求头传
        /// </summary>
        public Func<string> IgnoreSecretKeyFunc { get; set; }

        /// <summary>
        /// 是否启动，true为启动，false为关闭，默认为true
        /// </summary>
        public Func<bool> SetEnableFunc { get; set; }
    }
    /// <summary>
    /// 敏感数据加密
    /// </summary>
    public class SensitiveDataProvider
    {
        /// <summary>
        /// 敏感数据加密
        /// </summary>
        /// <param name="config"></param>
        public SensitiveDataProvider(SensitiveDataConfig config)
        {
            Config = config;
        }
        /// <summary>
        /// 敏感数据配置
        /// </summary>
        public SensitiveDataConfig Config { get; set; }

        /// <summary>
        /// 可忽略的密钥
        /// </summary>
        const string _IGNORE_SECRET_KEY = "3aed2fe84efb0f3b3106db8697060e93";

        /// <summary>
        /// 公开脱敏的密钥
        /// </summary>
        const string _PUBLIC_SECRET_KEY = "251de2b873df27a2e96abcf2745693b1";

        /// <summary>
        /// 密文前缀
        /// </summary>
        const string _PREFIX = "ZYS_";

        /// <summary>
        /// 公开脱敏的密文前缀
        /// </summary>
        const string _PUBLIC_PREFIX = "ZYSP_";

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="value">明文</param>
        /// <returns></returns>
        public object Encode(object value)
        {
            var enable = GetEnable();
            if (!enable)
            {
                return value;
            }
            if (string.IsNullOrEmpty(value + string.Empty))
            {
                return value;
            }
            var token = GetSecretKey();
            byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(value.ToString());
            DesEncodeDecode des = new DesEncodeDecode(token, System.Security.Cryptography.CipherMode.ECB, System.Security.Cryptography.PaddingMode.PKCS7, false);
            var buffer = des.DesEncrypt(byteArray);
            var result = Base58.Encode(buffer);
            if (token == _PUBLIC_SECRET_KEY)
            {
                return $"{_PUBLIC_PREFIX}{result}";
            }
            return $"{_PREFIX}{result}";
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="value">密文</param>
        /// <returns></returns>
        public object Decode(object value)
        {
            var enable = GetEnable();
            if (!enable)
            {
                return value;
            }
            if (string.IsNullOrEmpty(value + string.Empty))
            {
                return value;
            }
            var token = GetSecretKey();
            var ignoreKey = GetIgnoreSecretKey();
            string strValue = value + string.Empty;
            if (!strValue.StartsWith(_PREFIX) && !strValue.StartsWith(_PUBLIC_PREFIX))
            {
                if (ignoreKey == _IGNORE_SECRET_KEY)
                {
                    return value;
                }
                //强制脱敏
                throw new SensitiveDataException("抱歉，您当前账户缺少数据访问权限！");
            }
            try
            {

                if (strValue.StartsWith(_PUBLIC_PREFIX))
                {
                    //采用公有密钥
                    token = _PUBLIC_SECRET_KEY;
                    strValue = strValue.Substring(_PUBLIC_PREFIX.Length);
                }
                else
                {
                    strValue = strValue.Substring(_PREFIX.Length);
                }
                var byteArray = Base58.Decode(strValue);
                DesEncodeDecode des = new DesEncodeDecode(token, System.Security.Cryptography.CipherMode.ECB, System.Security.Cryptography.PaddingMode.PKCS7, false);
                var buffer = des.DesDecrypt(byteArray);
                string str = Encoding.UTF8.GetString(buffer);
                return str;
            }
            catch (Exception ex)
            {
                throw new SensitiveDataException("抱歉，您当前账户缺少数据访问权限,请刷新或者重新登录！", ex);
            }
        }

        private string GetSecretKey()
        {
            string key = _PUBLIC_SECRET_KEY;
            if (Config.SecretKeyFunc == null)
            {
                return key;
            }
            var secret = Config.SecretKeyFunc();
            if (string.IsNullOrEmpty(secret))
            {
                return key;
            }
            key += secret;
            return MD5Provider.Encode(key);
        }
        private string GetIgnoreSecretKey()
        {
            if (Config.IgnoreSecretKeyFunc == null)
            {
                return string.Empty;
            }
            var secret = Config.IgnoreSecretKeyFunc();
            return secret;
        }

        private bool GetEnable()
        {
            if (Config.SetEnableFunc == null)
            {
                return true;
            }
            var enable = Config.SetEnableFunc();
            return enable;
        }
    }
    /// <summary>
    /// 敏感数据异常
    /// </summary>
    public class SensitiveDataException : JaredsException
    {
        /// <summary>
        /// 敏感数据异常
        /// </summary>
        public SensitiveDataException() : base() { }
        /// <summary>
        /// 敏感数据异常
        /// </summary>
        /// <param name="msg"></param>
        public SensitiveDataException(string msg) : base(msg) { }
        /// <summary>
        /// 敏感数据异常
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        public SensitiveDataException(string msg, Exception ex) : base(msg, ex) { }
    }
}
